<?php

namespace App\Service;

use App\Cache\UserCache;
use App\Exception\BusinessException;
use App\Model\WxUserModel;
use App\Utils\WxBizDataCrypt;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Config\Annotation\Value;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;

class WxUserLoginService
{
    #[Value('wx_app_id')]
    protected string $wxAppId;

    #[Value('wx_app_secret')]
    protected string $wxAppSecret;

    #[Inject(ClientFactory::class)]
    protected ClientFactory $clientFactory;

    #[Inject(WxUserService::class)]
    protected WxUserService $userService;

    #[Inject(UserCache::class)]
    protected UserCache $userCache;


    /**
     * 获取openid，并保存
     * @throws GuzzleException
     */
    public function index(string $code, string|null $form): array
    {
        [$openid, $sessionKey] = $this->jscode2session($code);
        if ($user = $this->userCache->getByOpenid($openid)) {
            $user = $this->userService->updateUserByUser($user, ['session_key' => $sessionKey, 'from' => $form]);
        } else {
            $user = $this->userService->insertOne([
                'openid' => $openid,
                'session_key' => $sessionKey,
                'from' => $form ?: '',
            ]);
        }
        $this->userCache->set($openid, $user);
        return $user->toArray();
    }

    public function updatePhoneByEncrypted(string $encryptedData, string $iv, string $id): array
    {
        $user = WxUserModel::find($id);
        $pc = new WxBizDataCrypt($this->wxAppId, $user->session_key);
        $data = '';
        $errCode = $pc->decryptData($encryptedData, $iv, $data);
        if ($errCode === 0) {
            $res = json_decode($data, true);
            $user = $this->userService->updateUserByUser($user, [
                'phone' => $res['purePhoneNumber'],
                'country_code' => $res['countryCode'],
            ]);
            $this->userCache->set($user->openid, $user);
            return $res;
        } else {
            throw new BusinessException;
        }
    }

    /**
     * @param string $code
     * @return array
     * @throws GuzzleException | BusinessException
     */
    protected function jscode2session(string $code): array
    {
        $http = $this->clientFactory->create();
        $res = $http->get('https://api.weixin.qq.com/sns/jscode2session?appid=' . $this->wxAppId
            . '&secret=' . $this->wxAppSecret
            . '&js_code=' . $code
            . '&grant_type=authorization_code');
        if (($res->getStatusCode() === 200)
            && ($resClass = json_decode($res->getBody()->getContents()))
            && $resClass->session_key
            && $resClass->openid) {
            return [$resClass->openid, $resClass->session_key];
        } else {
            throw new BusinessException;
        }
    }
}